In [1]:
# %load_ext autoreload
# %autoreload 2

import os
import sys
import math
import pickle
import pandas as pd
import networkx as nx
import seaborn as sns
import matplotlib.pyplot as plt
from dataclasses import dataclass

sys.path.append(os.path.abspath(os.path.join(os.getcwd(), '..')))


from src.config import (
    PROCESSED_DATA_DIR,
)
from src import my_utils, community_detection, structural_analysis
Note: to be able to use all crisp methods, you need to install some additional packages:  {'graph_tool', 'leidenalg', 'wurlitzer', 'bayanpy', 'infomap'}
Note: to be able to use all crisp methods, you need to install some additional packages:  {'pyclustering', 'ASLPAw'}
Note: to be able to use all crisp methods, you need to install some additional packages:  {'wurlitzer', 'leidenalg', 'infomap'}
In [2]:
@dataclass
class Params:
    min_co_occurence_threshold: int = 5
    ws_rewire_probe: float = 0.4
    k_clique_percolation_base: int = 6 # (finding communities based on N-cliques)
    louvain_communities_resolution: float = 1 #  If resolution is less than 1, the algorithm favors larger communities. Greater than 1 favors smaller communities

params = Params()

1. Get Data¶

1.1 Edges Data¶

In [3]:
edges_data = (
    pd.read_csv(PROCESSED_DATA_DIR / "edges_data_processed.csv")
)

edges_data
Out[3]:
name1 name2 total_co_occurance books_appearance book_chapter co_occurance_chapters_cnt
0 Ammanas Laseen 91 9 2 24
1 Ammanas Ganoes Stabro Paran 33 6 2 16
2 Laseen Ganoes Stabro Paran 69 8 2 22
3 Ganoes Stabro Paran Laseen 8 4 2 4
4 Caladan Brood Dujek Onearm 94 6 2 19
... ... ... ... ... ... ...
4318 Blistig Tehol Beddict 8 1 15 1
4319 Icarium Ebron 6 1 15 1
4320 Icarium Tehol Beddict 7 1 15 1
4321 Sinter Vastly Blank 6 1 17 1
4322 Sandalath Drukorlat Sinter 6 1 17 1

4323 rows × 6 columns

1.2 Nodes Data¶

In [4]:
nodes_data = (
    pd.read_csv(PROCESSED_DATA_DIR / "nodes_data_processed.csv")
)
nodes_data.head()
Out[4]:
id norm_name gender info profession total_words_count books_appearance first_book_appearance last_book_appearance pov_words_per_book_with_pov ... race_first degree closeness betweenness eigenvector pagerank core_number k_clique_percolation louvain_community asyn_lpa_community
0 Apsalar apsalar Female -, aka Sorry, aka not-Apsalar, 9th Squad, Brid... Assassin 32604 3 1 6 10868 ... Human 0.079221 0.409181 0.031353 0.151144 0.005883 15 13 0 0.0
1 Lorn lorn Female Adjunct to the Empress Empress 18266 1 1 1 18266 ... Human 0.016883 0.349132 0.000304 0.050828 0.001354 12 0 0 0.0
2 Aragan aragan Male , staff sergeant Itko Kan, captain Mock's Hold... Guard 813 2 1 6 406 ... Human 0.001299 0.264996 0.000000 0.002511 0.000283 1 -1 0 0.0
3 Tattersail tattersail Female a mage of Malaz Island, Malazan Cadre Sorceres... Sorceress 25371 1 1 1 25371 ... Human 0.031169 0.350120 0.001345 0.069733 0.002319 14 0 0 0.0
4 Whiskeyjack whiskeyjack NaN once went by Jack, sergeant of the Bridgeburne... Guard 47344 2 1 3 23672 ... Human 0.077922 0.404278 0.017875 0.143569 0.005861 14 0 0 0.0

5 rows × 22 columns

1.3 Create nx.Graph¶

In [5]:
with open(PROCESSED_DATA_DIR / "graph.pkl", "rb") as f:
    G = pickle.load(f)

largest_cc = max(nx.connected_components(G), key=lambda cc: len(cc))
largest_cc_subgraph = G.subgraph(largest_cc)

2. Network Summary¶

2.1 Visualisation¶

In [6]:
pos = nx.spring_layout(largest_cc_subgraph, k=1/math.sqrt(len(largest_cc_subgraph)), iterations=50, seed=42)
nx.draw_networkx(
    largest_cc_subgraph,
    pos,
    with_labels=False,
    edge_color='gray',
    node_size=40,
    alpha=0.5,
    edgecolors='black'
)

2.2 Overview¶

In [7]:
_ = my_utils.get_graph_overview(G)
Number of Connected Components within a Graph: 7
Network Radius (largest CC): 5
Network Diameter (largest CC): 9
Avg. Clustering: 0.52
Avg. Shortest Path Length (largest CC): 3.492
In [8]:
my_utils.plot_power_degree_histogram(G)
In [9]:
my_utils.plot_power_degree_distribution(G)
In [10]:
analysis = my_utils.PowerLawAnalysis(G)
analysis.plot_distribution(title='Malazan Network Degree Distribution')

3. Structural Analysis¶

3.1 Malazan Network Comparison to Various Random Networks¶

In [11]:
structure_analyser = structural_analysis.NetworkStructuralAnalyser(G, ws_rewire_probe=params.ws_rewire_probe)
_ = structure_analyser.analyze_network_properties()
In [12]:
structure_analyser.plot_random_networks()

2.2 Centralities¶

In [13]:
structural_analysis.get_centrality(nodes_data, column_name='total_words_count', centrality_name='pov')
In [14]:
structural_analysis.get_centrality(nodes_data, column_name='degree', centrality_name='degree')
In [15]:
structural_analysis.get_centrality(nodes_data, column_name='closeness', centrality_name='closeness')
In [16]:
structural_analysis.get_centrality(nodes_data, column_name='betweenness', centrality_name='betweenness')
In [17]:
structural_analysis.get_centrality(nodes_data, column_name='eigenvector', centrality_name='eigenvector')
In [18]:
structural_analysis.get_centrality(nodes_data, column_name='pagerank', centrality_name='pagerank')
In [19]:
structural_analysis.plot_centralities_pairplot(nodes_data)
In [20]:
structural_analysis.plot_centralities_corr_matrix(nodes_data)
In [21]:
structure_analyser.plot_attribute_mixing(G, 'gender')
In [22]:
structure_analyser.plot_attribute_mixing(G, 'race_first')
In [23]:
structure_analyser.plot_attribute_mixing(G, 'affiliation_first')
In [24]:
structure_analyser.plot_attribute_mixing(G, 'affiliation_second')
In [25]:
structural_analysis.get_weights_between_top_nodes(nodes_data, G)
In [26]:
structure_analyser.plot_node_similarity_matrix(
    G, top_nodes=nodes_data.nlargest(20, 'degree')['id'].tolist(), similarity_metric='jaccard'
    )

3. Community Detection¶

In [27]:
community_detection.get_clique_size_distribution(G)
Out[27]:
Size Count
0 15 2
1 13 8
2 12 10
3 11 24
4 10 58
5 9 104
6 8 177
7 7 204
8 6 216
9 5 220
10 4 254
11 3 226
12 2 185
In [28]:
community_detection.find_top_n_cliques(G, 3)
Top 3 cliques found:

Clique 1:
Size: 15
Node IDs: ['Balm', 'Bottle', 'Deadsmell', 'Flashwit', 'Hellian', 'Jamber Bole', 'Kisswhere', 'Koryk', 'Limp', 'Masan Gilani', 'Mayfly', 'Sinter', 'Smiles', 'Tarr', 'Throatslitter']

Clique 2:
Size: 15
Node IDs: ['Balm', 'Bottle', 'Deadsmell', 'Flashwit', 'Hellian', 'Jamber Bole', 'Kisswhere', 'Koryk', 'Limp', 'Mayfly', 'Sinter', 'Smiles', 'Tarr', 'Throatslitter', 'Widdershins']

Clique 3:
Size: 13
Node IDs: ['Balm', 'Bottle', 'Deadsmell', 'Fiddler', 'Flashwit', 'Hellian', 'Jamber Bole', 'Koryk', 'Masan Gilani', 'Mayfly', 'Sinter', 'Smiles', 'Tarr']
In [29]:
gn = community_detection.GirvanNewmanAlgo(largest_cc_subgraph)
labels = gn.run(3)
gn.plot_communities()
In [30]:
kc = community_detection.KCliquePercolation(largest_cc_subgraph)
communities = kc.run(k=3)
kc.plot_communities()
In [31]:
fcu = community_detection.FastCommunityUnfolding(largest_cc_subgraph)
communities = fcu.run()
fcu.print_communities()
fcu.plot_communities()
2024-11-16 16:25:08.772 | INFO     | src.community_detection:print_communities:122 - Found 13 communities:
2024-11-16 16:25:08.785 | INFO     | src.community_detection:print_communities:124 - Community 1: [' Dark', 'Adaephon', 'Admiral Nok', 'Aimless', 'Alchemist', 'Ammanas', 'Anaster', 'Anomander Rake', 'Antsy', 'Apsalar', 'Apto', 'Aragan', 'Artanthos', 'Baruk', 'Bellurdan', 'Ben Adaephon Delat', 'Bendal Home', 'Blend', 'Bluepearl', 'Boil', 'Braven', 'Brukhalian', 'Bucklund', 'Bude', 'Cafal', 'Caladan Brood', 'Calot', 'Cannig Tol', 'Chained', 'Chal', 'Challice', 'Chole', 'Circle Breaker', 'Coll', 'Coop', 'Crippled God', 'Crone', 'Crust', "D'Arle", 'Darist', 'Dathenar', 'Dela', 'Derudan', 'Dessembrae', 'Detoran', 'Dujek Onearm', 'Durav', 'Endest', 'Endest Silann', "Estraysian D'Arle", 'Farakalian', 'Futhgar', 'Ganath', 'Ganoes Stabro Paran', 'Garsten', 'Gent', 'Gethol', 'Gorlas', 'Gorlas Vidikas', 'Gradithan', 'Gran', 'Hairlock', 'Hanut Orr', 'Hedge', 'Herald', 'Hetan', 'Hinter', 'Humbrall Taur', 'Hurlochel', 'Irilta', 'Itkovian', 'Jarak', 'Jelarkan', "K'rul", 'Kala', 'Kalam Mekhar', 'Kallor', 'Karnadas', 'Karpolan', 'Karpolan Demesand', 'Korlat', 'Krin', 'Kron', 'Kruppe', 'Krute', 'Krute of Talient', 'Laseen', 'Liss', 'Lock', 'Lorn', 'Lucky', 'Maker', 'Mallet', 'Mammot', 'Mebra', 'Meese', 'Mekhar', 'Mhybe', 'Moby', 'Monkrat', 'Mulch', 'Mull', 'Murillio', 'Nightchill', 'Nimander Golit', 'Noto', 'Noto Boil', 'Ocelot', 'Orfantal', 'Pallid', 'Pannion Seer', 'Picker', 'Polielmane', 'Pran', 'Pran Chole', 'Prazek Goul', 'Raest', 'Rallick Nom', "Rath'Ammanas", "Rath'Burn", "Rath'Fener", "Rath'Hood", "Rath'Treach", 'Runter', 'Rythe Bude', 'Salind', 'Salk', 'Scurve', 'Seba Krafar', 'Seerdomin', 'Shank', 'Silanah', 'Silverfox', 'Spindle', 'Spinnock', 'Spinnock Durav', 'Sulty', 'Sweetcreek', 'Talamandas', 'Tattersail', 'Tayschrenn', 'Thrall', 'Toc the Elder', 'Toc the Younger', 'Toes', 'Topper', 'Torun', 'Trotts', 'Turban Orr', 'Twist', 'Urko Crust', 'Vidikas', 'Vorcan', 'Whiskeyjack']
2024-11-16 16:25:08.785 | INFO     | src.community_detection:print_communities:124 - Community 2: ['Abrastal', 'Aranict', 'Autumn', 'Badalle', 'Banaschar', 'Bent', 'Beru', 'Blessed', 'Blistig', 'Braven Tooth', 'Brayderal', 'Could Howl', "D'rek", 'Exent Hadar', 'Faradan', 'Faradan Sort', 'Felash', 'Ffan', 'Gamet', 'Grub', 'Hadar', 'Hanavat', 'Hare Ravage', 'Held', 'Henar', 'Henar Vygulf', 'Imrahl', 'Jastara', 'Keneb', 'Kindly', 'Krughava', 'Lost', 'Lostara', 'Lostara Yil', 'Mallick Rel', 'Mowri', 'Nether', 'Outrider', 'Pearl', 'Pores', 'Pormqual', 'Raband', 'Rada', 'Ranal', 'Roach', "Run'Thurvian", 'Ruthan Gudd', 'Rutt', 'Saddic', 'Sample', 'Shelemasa', 'Sinn', 'Skanarow', 'Spax', 'Squint', "T'amber", 'Tanakalian', 'Tavore Paran', 'Temper', 'Temul', 'Tene Baralta', 'Togg', 'Tooth', 'Visto', 'Warleader Gall', 'Wolves', 'Wolves of Winter', 'Worm', 'Worm of Autumn']
2024-11-16 16:25:08.785 | INFO     | src.community_detection:print_communities:124 - Community 3: ['Calm', 'Diligence', 'Equity', 'Reverence', 'Seren Pedacity']
2024-11-16 16:25:08.786 | INFO     | src.community_detection:print_communities:124 - Community 4: ['Amby Bole', 'Baaljagg', 'Bain', 'Bainisk', 'Bauchelain', 'Bedek', 'Bellam', 'Bole', 'Broach', 'Buke', 'Cartographer', 'Emancipor', 'Faint', 'Glanno', 'Glanno Tarp', 'Gruntle', 'Harllo', 'Jula', 'Korbal', 'Korbal Broach', 'Lean', 'Mappo', 'Myrla', 'Netok', 'Precious Thimble', 'Quell', 'Reccanto', 'Reccanto Ilk', 'Reese', 'Rellock', 'Ryllandaras', 'Setoc', 'Snell', 'Stonny Menackis', 'Sufferance', 'Sweetest', 'Sweetest Sufferance', 'Venaz']
2024-11-16 16:25:08.786 | INFO     | src.community_detection:print_communities:124 - Community 5: ['Asane', 'Bairoth Gild', 'Beroke', 'Beroke Soft ', 'Boatfinder', 'Borrug', 'Damisk', 'Dayliss', 'Delum', 'Delum Thord', 'Gareb', 'Halad', 'Halad the Giant', 'Kahlb', 'Kahlb the Silent ', 'Kalt', 'Kalt Urmanal', 'Karsa Orlong', 'Lazan', 'Lazan Door', 'Leff', 'Lender', 'Madrun', 'Nappet', 'Nom Kala', 'Pahlk', 'Rall', 'Rautos', 'Scorch', 'Sheb', 'Silgar', 'Slavemaster', 'Studlock', 'Synyg', 'Taxilian', 'Thenik', 'Thenik the ', 'Thord', 'Torvald Nom', 'Urugal', 'Urugal the Woven', 'Veed']
2024-11-16 16:25:08.786 | INFO     | src.community_detection:print_communities:124 - Community 6: ['Alar', 'Baria', 'Baria Setral', 'Baudin', 'Beneth', 'Bidithal', 'Bodyguard', 'Bula', 'Bult', 'Bungle', 'Chenned', 'Chert', 'Coltaine', 'Crokus Younghand', 'Dreams', 'Drin', 'Duiker', 'Dunsparrow', 'Fast', 'Fayelle', 'Febryl', 'Felisin Paran', 'Felisin Paran the Younger', 'Flails', 'Grief', 'Gryllen', 'Hands', 'Heboric Light Touch', 'Heboric Light Touch Heboric Light Touch', 'Henaras', 'Kamist Reloe', 'Korbolo Dom', 'Kulp', "L'oric", 'Lenestro', 'Leoman', 'List', 'Lull', 'Mathok', 'Mesker Setral', 'Mincer', 'Nethpara', 'Pella', 'Polielfrog', 'Pullyk', 'Pullyk Alar', 'Sawark', 'Scillara', "Sha'ik", "Sormo E'nath", 'Sulmar', 'Summer', 'Talo Krafar', 'Tiger', 'Treach', 'Truth', 'Tumlit', 'Vatha', 'Whirlwind ']
2024-11-16 16:25:08.786 | INFO     | src.community_detection:print_communities:124 - Community 7: ['Able', 'Aparal Forge', 'Badan Gruk', 'Balgrid', 'Balm', 'Beak', 'Bell', 'Bellig Harn', 'Bordu', 'Borduke', 'Bottle', 'Brethless', 'Burnt', 'Clasp', 'Cora', "Corabb Bhilan Thenu'alas", "Corabb Bhilan Thenu'alas Thenu'alas", 'Cord', 'Cuttle', 'Deadsmell', 'Drawfirst', 'Ebron', 'Fiddler', 'Flashwit', 'Galt', 'Gentur', 'Gesler', 'Gilani', 'Hanno', 'Hanut', 'Hellian', 'Honey', 'Hunt', 'Jamber Bole', 'Kisswhere', 'Koryk', 'Legana', 'Legana Breed', 'Limp', 'Lobe', 'Lookback', 'Lutes', 'Masan', 'Masan Gilani', 'Mayfly', 'Moak', 'Mosel', 'Mudslinger', 'Mulvan Dreader', 'Nefarias Bredd', 'Neller', 'Nep Furrow', 'Pamby Doughty', 'Primly', 'Ramp', "Rath'", 'Reem', 'Reliko', 'Ruffle', 'Saltlick', 'Sands', 'Scant', 'Shard', 'Shoaly', 'Shortnose', 'Sinter', 'Skim', 'Skulldeath', 'Smiles', 'Sobelone', 'Stacker', 'Stormy', 'Strap Mull', "T'riss", 'Tarr', 'Tavos', 'Tavos Pond', "Thenu'alas", 'Thom Tissy', 'Throatslitter', 'Tissy', 'Touch', 'Touchy', 'Tugg', 'Tulip', 'Urb', 'Uru Hela', 'Vastly', 'Vastly Blank', 'Widdershins']
2024-11-16 16:25:08.786 | INFO     | src.community_detection:print_communities:124 - Community 8: ['Absi', 'Aral', 'Ay Estos', 'Barrakta Ilk', 'Bena', 'Bentract', 'Best', 'Druz Thennict', 'Generous', 'Gholan', "Gr'istanas Ish'ilm", 'Haran Epal', 'Hentos Ilm', 'Hostille Rator', 'Ibra', 'Ibra Gholan', 'Kesen', 'Kilava', 'Logros', 'Minala', 'Monok', 'Monok Ochem', 'Ochem', 'Olar Shayn', "Onrack T'emlava", "Onrack T'emlava ", 'Panek', 'Pral', 'Rud Ellale', 'Selv', 'Stavi', 'Storii', "Til'aras Benok", 'Ulshun', 'Ulshun Pral', 'Vaneb']
2024-11-16 16:25:08.786 | INFO     | src.community_detection:print_communities:124 - Community 9: ['Ahlrada', 'Ahlrada Ahn', 'Arahathan', 'Bars', 'Beddict', 'Binadas Sengar', 'Blind Warleader Gallan', 'Boaral', 'Bowl', 'Brevity', 'Brizad', 'Brullyg', 'Bruthen Trana', 'Brys Beddict', 'Bubyrd', 'Bugg', 'Buhn', 'Buruk the Pale', 'Canar', 'Canarth', 'Choram Irard', 'Consort', 'Corlo', 'Cough', 'Derryg', 'Diskanar', 'Eberict', 'Enedictal', 'Errant', 'Ezgara', 'Ezgara Diskanar', 'Feather', 'Feather Witch', 'Gerun', 'Gerun Eberict', 'Glisten', 'Hannan Mosag', 'Hanradi', 'Hanradi Khalag', 'Harlest', 'Harlest Eberict', 'Hejun', 'Hivanar', 'Hulad', 'Huldo', 'Hull Beddict', 'Humble', 'Invictad', 'Iron Bars', 'Janall', 'Janath Anar', 'Karos', 'Karos Invictad', 'Kettle', 'Kholb', 'Kholb Harat', 'Kuru Qan', 'Matra Brith', 'Mayen', 'Midik', 'Midik Buhn', 'Moroch', 'Moroch Nevath', 'Mottle', 'Nekal Bara', 'Nevath', 'Nifadas', 'Nisall', 'Nithe', 'Onyx', 'Ormly', 'Pinosel', 'Pithy', 'Pully', 'Pung', 'Quillas', 'Quillas Diskanar', 'Rhulad Sengar', 'Rissarh', 'Ruby', 'Rucket', 'Samar Dev', 'Sathbaro Rangar', 'Scint', 'Selush', 'Seren Pedac', 'Shand', 'Shurq Elalle', 'Sirryn', 'Skorgen', 'Skorgen Kaban', 'Skwish', 'Stone', 'Tanal', 'Tanal Yathvanar', 'Taralack', 'Taralack Veed', 'Tehol Beddict', 'Theradas', 'Theradas Buhn', 'Tomad', 'Tomad Sengar', 'Tovis', 'Triban Gnol', 'Trull Sengar', 'Ublala', 'Ublala Pung', 'Udinaas', 'Unnutal', 'Unnutal Hebaz', 'Ursto', 'Ursto Hoobutt', 'Uruth Sengar', 'Varat', 'Varat Taun', 'Ventrala', 'White ', 'Yan Tovis', 'Yathvanar', 'Yedan Derryg']
2024-11-16 16:25:08.786 | INFO     | src.community_detection:print_communities:124 - Community 10: ['Aloft', 'Ampelas', 'Andarist', 'Anomandaris', 'Ardata', 'Aval', 'Bahann', 'Bakal', 'Bara', 'Baran', 'Barathol Mekhar', 'Betrayer', 'Blind', 'Brolos Haran', 'Chaur', 'Cotillion', 'Curdle', 'Dawn', 'Ditch', 'Draconus', 'Drethdenan', 'Edge', 'Edgewalker', 'Eloth', 'Envy', 'Erule', 'Esthala', 'Ethil', 'Fenar', 'Filiad', 'Fisher', 'Freedom', 'Garath', 'Gear', 'Grave', 'Hayrith', 'Hish', 'Hish Tulla', 'Hust', 'Icarium', 'Ilgast Rend', 'Ilm Absinos', 'Iparth', 'Iskaral Pust', 'Jhelim', 'Kadagar Fant', 'Kadaspala', 'Kagamandra Tulas', 'Kalse', 'Kashat', 'Kessobahn', 'Kilmandaros', 'Korabas', 'Kulat', 'Lanas Tog', 'Lath', 'Manalle', 'Mappo Runt', 'Maral Eb', 'Menand', 'Menandore', 'Mogora', 'Nulliss', 'Olar', 'Olar Ethil', "Onos T'oolan", 'Osseric', 'Ralata', 'Rood', 'Rystalle Ev', 'Saviour', 'Scabandari Bloodeye', 'Sechul Lath', 'Sekara', 'Senu', 'Shan', 'Sheltatha Lore', 'Shorn', 'Silann', 'Silchas Ruin', 'Sordiko Qualm', 'Sorrit', 'Spite', 'Stolmen', 'Strahl', 'Sukul Ankhadu', 'Taun', 'Telorast', 'Thurule', 'Torrent', 'Tulas', 'Tulas Shorn', 'Ulag', 'Ulag Togtil', 'Vanut', 'Vanut Degalla', 'Wither']
2024-11-16 16:25:08.786 | INFO     | src.community_detection:print_communities:124 - Community 11: ['Acyl', 'Bivatt', "Bre'nigan", 'Brohl', 'Brohl Handar', 'Capalah', 'Elan', "Gu'Rull", 'Gunth Mach', "Gunth Mach'an Acyl", 'Hadralt', "J'an", 'Kalyth', 'Kor Thuran', 'Letur Anict', 'Mach', 'Malle', 'Masarch', 'Natarkas', 'Orbyn', 'Orbyn Truthfinder', 'Rautos Hivanar', 'Redmask', 'Rythok', "Sag'Churok", 'Sentinel', 'Truthfinder', 'Venitt', 'Venitt Sathad']
2024-11-16 16:25:08.786 | INFO     | src.community_detection:print_communities:124 - Community 12: ["Apsal'ara", 'Aranatha', 'Clip', 'Desra', 'Kedeviss', 'Nenanda', 'Nimander', 'Phaed', 'Sandalath Drukorlat', 'Skint', 'Skintick', 'Withal']
2024-11-16 16:25:08.786 | INFO     | src.community_detection:print_communities:124 - Community 13: ['Bavedict', 'Nose', 'Rumjugs', 'Stream', 'Sunrise', 'Sweetlard']
In [32]:
wt = community_detection.Walktrap(largest_cc_subgraph)
communities = wt.run()
wt.plot_communities()
In [33]:
lpa = community_detection.LPACommunityDetection(largest_cc_subgraph, weight='total_co_occurance')
communities = lpa.run()
lpa.plot_communities()
2024-11-16 16:25:11.626 | INFO     | src.community_detection:run:258 - Successfully detected 73 communities using LPA